﻿/************************************************************************
 * AIDE - Automata Identification Engine
 * Copyright (C) 2012-2013 Ali Khalili (khalili_DOT_ir_@SIGN_gmail_DOT_com)
 * **********************************************************************
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License (LGPL) published 
 * by the Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version. This program is distributed without any
 * warranty. See the GNU Lesser General Public License for more details. 
 * ***********************************************************************
 * File         :     AIDE\OnlineAlgo\IAs\IAWrapperInNFM.cs
 * Description  :     The wrapper of IA in NFM
 * Change log   :     -April 2013:  Initial Development
 * To Do        :
 ************************************************************************/
using System;
using System.Collections.Generic;
using SMLib.Automata.MM;
using SMLib.Automata.Base;
using SMLib.Automata.IA;

namespace AIDE.Learning.IA_Learning
{
    /// <summary>
    /// Translator between Mealy Learner and IA SUL (both online and offline).
    /// <remarks>It is a kind of wrapping an IA system in a Mealy machine!</remarks>
    /// </summary>
    public class IAWrapperInNFM : IBlackBox_MM
    {
        IBlackBox_IA sul;
        ISymbol OkSym, DeltaSym;
        Alphabet inputAlphabet;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="sulStepper">the System Under Learning</param>
        public IAWrapperInNFM(IBlackBox_IA sul)
        {
            this.sul = sul;
            OkSym = new StringSymbol("OK");
            DeltaSym = new StringSymbol("Delta");


            inputAlphabet = new Alphabet();
            foreach (ISymbol symb in sul.InputAlphabet.AllSymbols())
            {
                inputAlphabet.AddSymbol(symb);
            }
            inputAlphabet.AddSymbol(DeltaSym);
        }

        #region IA2NFM and NFM2IA (offline translation)

        /// <summary>
        /// Convert an IA into NFM
        /// </summary>
        /// <param name="iolts">the Interface Automata (to be translated)</param>
        /// <returns>the resulting Mealy machine</returns>
        public static MealyMachine ConvertToMealy(InterfaceAutomaton iolts)
        {
            ISymbol DeltaSym = new StringSymbol("Delta"), OkSym = new StringSymbol("OK");
            MealyMachine m = new MealyMachine();
            for (int i = 0; i < iolts.Size; i++)
            {
                MealyMachine.Mealy_State st = new MealyMachine.Mealy_State(i.ToString());
                m.AddState(st);
            }

            int index = 0;
            foreach (InterfaceAutomaton.IA_State st in iolts.GetStates())
            {
                foreach (InterfaceAutomaton.IA_Step tr in st.Transitions)
                {
                    //* it is an observable event
                    if (tr.StepType == InterfaceAutomaton.IA_Step.Step_Type.EVENT)
                    {
                        //InterfaceAutomaton.IA_Step t = new InterfaceAutomaton.IA_Step(tr.outLabel, false);
                        //MealyMachine.Mealy_Transition t = new MealyMachine.Mealy_Transition(DeltaSym, (ISymbol)tr.Label);
                        //t.SetDestination((MealyMachine.Mealy_State)iolts[iolts.IndexOf(tr.Destination)]);
                        ((MealyMachine.Mealy_State)m[index]).AddTransition(
                            (MealyMachine.Mealy_State)m[iolts.IndexOf(tr.Destination)], DeltaSym, (ISymbol)tr.Label);
                    }
                    //* it is a controllable action
                    else if (tr.StepType == InterfaceAutomaton.IA_Step.Step_Type.ACTION)
                    {
                        ((MealyMachine.Mealy_State)m[index]).AddTransition(
                            (MealyMachine.Mealy_State)m[iolts.IndexOf(tr.Destination)], (ISymbol)tr.Label, OkSym);
                    }
                }
                index++;
            }

            return m;
        }

        /// <summary>
        /// Convert a NFM into IA
        /// </summary>
        /// <param name="nfm">the nondeterministic Mealy machine (to be translated)</param>
        /// <returns>the resulting IA</returns>
        public static InterfaceAutomaton ConvertToIOLTS(MealyMachine nfm)
        {
            ISymbol DeltaSym = new StringSymbol("Delta"), OkSym = new StringSymbol("OK");
            InterfaceAutomaton iolts = new InterfaceAutomaton();
            for (int i = 0; i < nfm.Size; i++)
            {
                InterfaceAutomaton.IA_State st = new InterfaceAutomaton.IA_State(i);
                iolts.AddState(st);
            }
            int index = 0;
            foreach (MealyMachine.Mealy_State st in nfm.GetStates())
            {
                foreach (MealyMachine.Mealy_Transition tr in st.Transitions)
                {
                    //* it is an observable event
                    if (tr.inLabel.Equals(DeltaSym))
                    {
                        InterfaceAutomaton.IA_Step t = new InterfaceAutomaton.IA_Step(tr.outLabel, false);
                        t.SetDestination((InterfaceAutomaton.IA_State)iolts[nfm.IndexOf(tr.Destination)]);
                        ((InterfaceAutomaton.IA_State)iolts[index]).AddTransition(t);
                    }
                    //* it is a controllable action
                    else if (tr.outLabel.Equals(OkSym))
                    {
                        InterfaceAutomaton.IA_Step t = new InterfaceAutomaton.IA_Step(tr.inLabel, true);
                        t.SetDestination((InterfaceAutomaton.IA_State)iolts[nfm.IndexOf(tr.Destination)]);
                        ((InterfaceAutomaton.IA_State)iolts[index]).AddTransition(t);
                    }
                }
                index++;
            }
            return iolts;
        }
        #endregion

        #region IBlackBox_MealyMachine Members (online translation)
        /// <summary>
        /// Reset the system
        /// </summary>
        public void Reset()
        {
			//AIDE.Base.LearningLog.DoRealReset ();
            sul.Reset();
        }

        /// <summary>
        /// Execute an action
        /// <remarks>[Convention: as always, if the action is not enabled, it returns null]</remarks>
        /// </summary>
        /// <param name="input">the input symbol</param>
        /// <returns>if it is null, it means that the input is not enabled!</returns>
        public ISymbol Step(ISymbol input)
        {
            //* asking for the output
            if (input.Equals(DeltaSym))
            {
                if (sul.EventAvailable())
                    return sul.Event();
                else
                    return null;
            }
            //* asking for execution of an action
            else
            {
                try
                {
                    sul.Perform(input);
                }
                catch (NotEnabledActionException)
                {
                    return null;
                }
                return OkSym;
            }
        }

        /// <summary>
        /// The input alphabet (set of controllable actions) of IA
        /// </summary>
        public Alphabet InputAlphabet
        {
            get { return inputAlphabet; }
        }

        #endregion
    }
}
